import java.util.Iterator;
import org.apache.uima.*;
import org.apache.uima.analysis_component.JCasAnnotator_ImplBase;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.text.AnnotationIndex;
import org.apache.uima.jcas.JCas;
import java.lang.reflect.*;

import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.jxpath.*;
import org.apache.commons.jxpath.xml.DocumentContainer;


public class typeMappingAnalysisEngineAnnotator extends JCasAnnotator_ImplBase {

	private static String XML_FILE = "xmlFile";
	private String sourceTypeStr;
	private String targetTypeStr;
	private static URL urlXmlFile;
//On suppose que le fichier Xml est contenu dans le répertoire xml situé dans le path du projet
	public void initialize(UimaContext context) 
	{
		
		try {
			
			//Récupération du paramètre, le nom du fichier XML
			XML_FILE = (String) context.getConfigParameterValue(XML_FILE);
			String strUrl = "file://"+System.getProperty("user.dir")+"/xml/"+XML_FILE;
			//Création d'une URL à partir de ce nom
			urlXmlFile = new URL(strUrl);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		
		//Création d'un DocumentContainer contenant notre fichier Xml
		DocumentContainer monDoc = new DocumentContainer(urlXmlFile);
		//Création d'un JXPathContext à partir de ce DocumentContainer
		JXPathContext jxpathContext = JXPathContext.newContext(monDoc);
		
		//Requête XPath pour la source
		String xpath = "//SOURCE";
		//On récupère le résultat (soit le type de la source)
		sourceTypeStr = (String)jxpathContext.getValue(xpath);
		
		//Requête XPath pour la target
		xpath = "//TARGET";
		//On récupère le résultat (soit le type de la target)
		targetTypeStr = (String)jxpathContext.getValue(xpath);
		
	}

	
	public void process(JCas aJCas) throws AnalysisEngineProcessException {
		
		//Récupération du type source
		Type typeSrc = aJCas.getTypeSystem().getType(sourceTypeStr);

		//Dans le cas où le type source n'existe pas		
		if (typeSrc == null)
		{
			String errmsg = "Le type " + sourceTypeStr + " n'est pas déclaré dans le TypeSystem !";
		    throw new AnalysisEngineProcessException(errmsg, new Object[]{typeSrc});			
		}
		
		//EXECUTION NORMALE
		try{
		//Génération des classes correspondants aux Strings sourceTypeStr et targetTypeStr
		Class SrcClass = Class.forName(sourceTypeStr);
		Class TgtClass = Class.forName(targetTypeStr);
		
		//Génération des constructeurs des classes source/target
		Constructor srcConstr = SrcClass.getConstructor(new Class [] {JCas.class});
		Constructor tgtConstr = TgtClass.getConstructor(new Class [] {JCas.class});

		//Récupération de l'ensemble/index des annotations du type source
		AnnotationIndex idxSrc = (AnnotationIndex)aJCas.getAnnotationIndex(typeSrc);
		
		//Création d'un itérateur sur cet index
		Iterator itSrc = idxSrc.iterator();

		//Tant qu'il y a des annotations de type source
		while(itSrc.hasNext())
		{
			//Création de l'annotation courante
			Object s = srcConstr.newInstance(new Object [] {aJCas});
			s = itSrc.next();
			SrcClass.cast(s);	//On caste l'objet en type de SrcClass
			
			//On place l'environnement sur la SentenceWTKA courante
			JXPathContext jxpathContext = JXPathContext.newContext(s);
			
			//Création d'un tableau d'objet null
			Object[] args = null;
			Iterator itTA = jxpathContext.iterate("SentenceAnnotation");
			int size = jxpathContext.selectNodes("begin").size();
			System.out.println("#######Taille: "+size);
				while(itTA.hasNext()){
					
					jxpathContext= JXPathContext.newContext(itTA.next());
					//Récupération du début de l'annotation courante
					int begin = (Integer)jxpathContext.getValue("begin");
					
					//Récupération du début de l'annotation courante
					int end = (Integer)jxpathContext.getValue("end");
					
					//Récupération du Covered text de l'annotation courante
					String coveredText = (String)jxpathContext.getValue("coveredText");
					
					//Récupération du posTag de l'annotation courante
					//String pos = (String)jxpathContext.getValue("posTag");
					
					System.out.println("text "+coveredText+ " begin " +begin + " end "+ end);
					
					//Création d'une annotation du type target
					Object t = tgtConstr.newInstance(new Object [] {aJCas});
					TgtClass.cast(t);
					jxpathContext = JXPathContext.newContext(t);
					//Récupération de la méthode addToIndexes de la classe target
					Method addToIndexes = TgtClass.getMethod("addToIndexes", new Class[] {});
					
					//Ajouts à l'annotation du type target
					jxpathContext.setValue("begin", begin);
					jxpathContext.setValue("end", end);
					//jxpathContext.setValue("nature",pos);
					//JXPathContext.newContext(t).setValue("nature",pos);
					addToIndexes.invoke(t,args);
				}
		}
		}
				catch (IllegalArgumentException e) 
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
				catch (IllegalAccessException e) 
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
				catch (InvocationTargetException e) 
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
